module arm.peripheral;

import arm;

import arm.misc;
import std.traits : isNumeric;
import std.meta : allSatisfy;

import chip;

import core.volatile;
deprecated:
version(NONE):
/// 寄存器可用读写方式
enum Access
{
    none = 0,
    // byte
    bit_8 = 1u << 1,
    // short
    bit_16 = 1u << 2,
    // int
    bit_32 = 1u << 3,
    // 读取
    read = 1u << 4,
    // 写入
    write = 1u << 5,

    clear = 1u << 6,
    set = 1u << 7,
    toggle = 1u << 8,

    w0 = 1u << 9,
    w1 = 1u << 10,

    read8 = read | bit_8,
    read16 = read | bit_16,
    read32 = read | bit_32,

    write8 = write | bit_8,
    write16 = write | bit_16,
    write32 = write | bit_32,

    // 字节读写
    rw = read | write,
    ro = read,
    wo = write,
    rwa = 1u << 31,
}

/*
    全部采用模板方式加载
*/

/// 判定位可读
template CanRead(Access v)
{
    enum CanRead = (
        (v & Access.read) || 
        (v & Access.w0) ||
        (v & Access.w1) ||
        (v & Access.set) ||
        (v & Access.clear)
        );
}
/// 判定位可写
template CanWrite(Access v)
{
    enum CanWrite = (
        (v & Access.write) ||
        (v & Access.w0) ||
        (v & Access.w1) ||
        (v & Access.set) ||
        (v & Access.clear)
    );
}
/// 判定位可清除
template CanClear(Access v)
{
    enum CanClear = (
        (v & Access.clear) ||
        (v & Access.w0) ||
        (v & Access.w1) ||
        (v & Access.set)
        );
}

/// 返回寄存器内存操作对象类型
template regType(size_t width)
{
    private alias Tuple(A...) = A;
    private alias alltype = Tuple!(ubyte,ushort,uint);

    static if(width <= 1){
        alias regType = bool;
    }else{
        static foreach(v;alltype)
        {
            static if(width == v.sizeof*8) alias regType = v;
        }
    }
    static if(!__traits(compiles, regType.sizeof))
    {
        static assert(0,"not regtype");
    }

}

/// 外设寄存器接口
abstract class Peripheral(size_t paddress)
{
    //import core.atomic;
    // 采用core.volatile可以更节约存储空间
    

    public{
        /// 外设地址
        enum PeripheralAddress = paddress;
    }
    
    protected abstract class Register(size_t offset,Access access)
    {
        /// 当前寄存器访问地址
        public enum size_t RegistersAddress = PeripheralAddress + offset;
        /// 读写权限
        enum Access RegistersAccess = (access & Access.rwa)?Access.rw:access;
        /// 寄存器类型
        alias RegistersType = regType!SVDWidth;
        // shared 读写地址
        //enum shared(RegistersType*) RegistersBase = cast(shared RegistersType*)RegistersAddress;
        /// 寄存器可读
        enum RegRead = CanRead!(RegistersAccess);
        /// 寄存器可写
        enum RegWrite = CanWrite!(RegistersAccess);
        /// 寄存位带区可用
        enum isBitBandable = CheckBitBandable!(RegistersAddress);

        /// 位操作
        abstract class Bits(size_t mOffset,size_t bitSize,Access access)
        {
            /// 位地址
            enum Access bitsAccess = (access & Access.rwa)?Access.rw:access;
            /// 位可读
            enum BitRead = (CanRead!(bitsAccess) && RegRead);
            /// 位可写
            enum BitWrite = (CanWrite!(bitsAccess) && RegWrite);
            /// 有效取值位掩码
            enum BitMask = MakerMask!(0,mOffset + bitSize);
            /// 寄存器值掩码
            enum RegMask = MakerMask!(mOffset,mOffset + bitSize);

            // 返回类型
            static if (bitSize <= 1u){
                alias bitsType = bool;
            }else static if (bitSize <= ubyte.sizeof*8){
                alias bitsType = ubyte;
            }else static if (bitSize <= ushort.sizeof*8){
                alias bitsType = ushort;
            }else static if (bitSize <= uint.sizeof*8){
                alias bitsType = uint;
            }else{
                static assert(0,"T.sizeof > uint.sizeof");
            }
            //
            enum _valMin = bitsType.min;
            //
            static if(is(bitsType == bool)){
                enum _valMax = true;
            }else{
                enum _valMax = bitsType.max >> ((bitsType.sizeof * 8) - bitSize);
            }

            static if(BitWrite)
            pragma(inline,true)
            @property static void val(bitsType v) 
            {
                write4slice!(mOffset,bitSize)(cast(uint)v);
            }
            
            static if(BitRead)
            pragma(inline,true)
            @property static bitsType val()
            {
                auto v1 = read4slice!(mOffset,bitSize)();
                return cast(typeof(return))v1;
            }
        }

        // 读取函数
        static if(RegRead)
        {
            pragma(inline,true)
            static @property auto value()
            {
                return  volatileLoad(cast(RegistersType*)RegistersAddress);
            }

            /// 通过标记位的起始和结束位,读取数据切片
            pragma(inline,true)
            static bool read4slice(size_t _start,size_t _count)() if((_count == 1) && isBitBandable)
            {
                /// BitBandable 读写地址
                enum bitaddress = BitBand!(RegistersAddress,_start);
                return (volatileLoad(cast(uint*)bitaddress) & 0x01)?true:false;
            }
            /// 通过标记位的起始和结束位,读取数据切片
            //pragma(inline,true)
            static uint read4slice(size_t _start,size_t _count)() if(!isBitBandable || (_count > 1))
            {
                /// 数据结束位
                enum _end = _start + _count;
                /// 取位掩码
                enum mask = MakerMask!(_start,_end);
                /// 按位读取地址
                auto ret = volatileLoad(cast(uint*)RegistersAddress) & mask;
                /// 清除结果右侧位
                ret >>= _start;
                return ret;
            }
        }
        
        // 写入函数
        static if(RegWrite)
        {
            pragma(inline,true)
            static @property void value(RegistersType v)
            {
                volatileStore(cast(RegistersType*)RegistersAddress,v);
            }

            /// 通过标记位的起始和结束位,写入数据切片
            pragma(inline,true)
            static void write4slice(size_t _start,size_t _count,T)(T v)  if( isBitBandable && (_count == 1))
            {
                /// BitBandable 读写地址
                enum bitaddress = BitBand!(RegistersAddress,_start);
                //atomicStore(*cast(shared(uint)*)bitaddress, (v & 0x01u));
                
                // todo: 未实现原子操作
                volatileStore(cast(uint*)bitaddress, (v & 0x01u));
            }

            //pragma(inline,true)
            static void write4slice(size_t _start,size_t _count,T)(T v) if(!isBitBandable || (_count > 1))
            {
                /// 结束位
                enum _end = _start + _count;
                /// 取位掩码
                //enum mask = MakerMask4Slice!(_start,_end);
                enum mask = MakerMask!(_start,_end);

                // 移动位
                v <<= _start;

                // 判定原值是否可读
                static if(CanRead!RegistersAccess)
                {
                    // 获取历史值
                    uint oldval = value() & ~mask;
                    // 合并新值
                    v |=  oldval;
                }
                /// todo: 未实现原子操作
                volatileStore(cast(RegistersType*)RegistersAddress, v);
            }
        }
    }

    /// 获取内存地址
    pragma(inline,true)
    static @property auto GetAddress() 
    {
        return cast(immutable) PeripheralAddress;
    }


}

